package view;

import AStar.Grid;
import controller.Controle;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
import model.Node;
import model.Pesos;

/**
 *
 * @author Carlos Henrique Silva Galdino
 * @author Raphael Pereira de Faria
 *
 */
public class Janela extends JFrame {

    private PainelJanela painelDesenho;
    private String nomeRadios[] = { "Ponto inicial", "Ponto final", "Grama", "Pântano", "Obstáculo" };
    private ButtonGroup grupo;
    private JRadioButtonMenuItem radioButtons[];
    private int tipoPonto;
    private Grid grid;
    private JMenuItem botaoCaminho;
    private Controle controle;
    private PainelInfo painelInfo;

    /**
     * Construtor do Frame
     * @param titulo título do frame
     * @param cont1  objeto da classe controle
     */
    public Janela(String titulo, Controle cont1) {
        super(titulo);
        this.controle = cont1;
        this.grid = controle.getGrid();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(710, 785);
        setResizable(false);
        setLocationRelativeTo(null);
        getContentPane().add(criaMenu(), BorderLayout.NORTH);
        painelInfo = new PainelInfo();
        getContentPane().add(painelInfo, BorderLayout.SOUTH);
        painelDesenho = new PainelJanela();
        painelDesenho.addMouseListener(new MouseAdapter() {

            @Override
            public void mousePressed(MouseEvent e) {
                try {
                    // Captura a coordenada do clique
                    Point p = new Point(interacaoMouse(e.getX(), e.getY()));

                    // Remove o ponto do caminho se for o caso
                    controle.removePontoCaminho(p.x, p.y);

                    if (p.equals(grid.getNohInicial().getCoord()) || p.equals(grid.getNohFinal().getCoord())) {
                        grid.removerPonto(p);
                    }

                    // Clique com o botão esquerdo do mouse insere o ponto no grid
                    controle.removePontoCaminho(p.x,p.y);

                    if (p.equals(grid.getNohInicial().getCoord()) || p.equals(grid.getNohFinal().getCoord())) {
                        grid.removerPonto(p);
                    }
                    if (e.getButton() == MouseEvent.BUTTON1) {
                        // Remove o ponto caso clique em cima de outro ponto já inserido
                        if (tipoPonto <= 1) {
                            grid.removerPonto(p);
                        }
                        switch (tipoPonto) {
                            case 0: grid.setNohInicial(new Node(p, 1));
                                    break;
                            case 1: grid.setNohFinal(new Node(p, 1));
                                    break;
                            default: grid.adicionarTerreno(new Node(p, Pesos.valueOf(nomeRadios[tipoPonto].toUpperCase()).getPeso()));
                        }
                    }
                    // Clique com o botão direito do mouse remove o ponto do grid
                    if (e.getButton() == MouseEvent.BUTTON3) {
                        grid.removerPonto(p);
                    }
                    // Verificação se há possibilidade de procurar caminho
                    if (grid.getNohInicial().getCoord().x > -1 && grid.getNohFinal().getCoord().x > -1)
                        botaoCaminho.setEnabled(true);
                    else
                        botaoCaminho.setEnabled(false);
                    repaint();
                } catch (NullPointerException exc) {
                }
            }
        });

        painelDesenho.addMouseMotionListener(new MouseMotionListener() {

            public void mouseMoved(MouseEvent event) {
            }

            public void mouseDragged(MouseEvent e) {
                try {
                    // Captura a coordenada do clique
                    Point p = new Point(interacaoMouse(e.getX(), e.getY()));

                    // Remove o ponto do caminho se for o caso
                    controle.removePontoCaminho(p.x, p.y);

                    if (p.equals(grid.getNohInicial().getCoord()) || p.equals(grid.getNohFinal().getCoord())) {
                        grid.removerPonto(p);
                    }

                    // Remove o ponto caso clique em cima de outro ponto já inserido
                    if (tipoPonto <= 1) {
                        grid.removerPonto(p);
                    }

                    switch (tipoPonto) {
                        case 0:
                            grid.setNohInicial(new Node(p, 1));
                            break;
                        case 1:
                            grid.setNohFinal(new Node(p, 1));
                            break;
                        default:
                            grid.adicionarTerreno(new Node(p, Pesos.valueOf(nomeRadios[tipoPonto].toUpperCase()).getPeso()));
                    }
                    // Verificação se há possibilidade de procurar caminho
                    if (grid.getNohInicial().getCoord().x > -1 && grid.getNohFinal().getCoord().x > -1) {
                        botaoCaminho.setEnabled(true);
                    } else {
                        botaoCaminho.setEnabled(false);
                    }
                    repaint();
                } catch (NullPointerException exc) {
                }
            }
        });
        getContentPane().add(painelDesenho);
        setVisible(true);
    }

    /**
     * Método que constrói o menu
     * @return barra de menu
     */
    private JMenuBar criaMenu() {
        JMenuBar barraMenu = new JMenuBar();
        JMenu principal = new JMenu("Principal");
        botaoCaminho = new JMenuItem("Procurar caminho");
        botaoCaminho.setEnabled(false);
        botaoCaminho.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                controle.procurarCaminho();
                painelInfo.atualizarLabels(controle.getCusto(), controle.getCaminho().size());
                repaint();
            }
        });

        JMenuItem botaoSair = new JMenuItem("Sair");
        botaoSair.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        principal.add(botaoCaminho);
        principal.add(botaoSair);

        JMenu terrenos = new JMenu("Tipos de pontos");
        grupo = new ButtonGroup();
        radioButtons = new JRadioButtonMenuItem[nomeRadios.length];
        Gerenciador gerenciador = new Gerenciador();
        for (int i = 0; i < nomeRadios.length; i++) {
            radioButtons[i] = new JRadioButtonMenuItem(nomeRadios[i]);
            terrenos.add(radioButtons[i]);
            grupo.add(radioButtons[i]);
            radioButtons[i].addItemListener(gerenciador);
        }
        radioButtons[0].setSelected(true);
        barraMenu.add(principal);
        barraMenu.add(terrenos);

        return barraMenu;
    }

    /**
     * Método que captura a coordenada relativa ao clique no grid
     * @param x - valor do clique no eixo x
     * @param y - valor do clique no eixo y
     * @return ponto contendo a coordenada no grid
     */
    private Point interacaoMouse(int x, int y) {
        x /= 15;
        y /= 15;
        x--;
        y--;
        if (x < 0 || y > 44 || x > 44 || y < 0) {
            return null;
        }
        return new Point(x, y);
    }

    /**
     * Classe que gerencia a mudança de estados dos radioButtons
     */
    private class Gerenciador implements ItemListener {
        public void itemStateChanged(ItemEvent e) {
            for(int i = 0; i < radioButtons.length; i++) {
                if(radioButtons[i].isSelected())
                    tipoPonto = i;
            }
        }
    }

    /**
     * Classe que representa o painel onde tudo é desenhado
     */
    public class PainelJanela extends JPanel {

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.clearRect(0, 0, grid.getLargura() * 15, grid.getAltura() * 15);
            int TAM = 15;

            // Desenha todos os quadrados do grid
            for (int x = 1; x <= grid.getAltura(); x++) {
                for (int y = 1; y <= grid.getLargura(); y++) {
                    g.setColor(Color.GRAY);
                    g.drawRect(x * TAM, y * TAM, TAM, TAM);
                }
            }

            // Pinta o ponto inicial
            if (grid.getNohInicial().getCoord().x > -1) {
                Point ponto = grid.getNohInicial().getCoord();
                fillRectangle(g, ponto, TAM, Color.BLUE);
            }

            // Pinta o ponto final
            if (grid.getNohFinal().getCoord().x > -1) {
                Point ponto = grid.getNohFinal().getCoord();
                fillRectangle(g, ponto, TAM, Color.RED);
            }

            // Pinta todos os tipos de terrenos além dos obstáculos
            if (!grid.getObstaculos().isEmpty()) {
                for (Node noh : grid.getObstaculos()) {
                    Point ponto = noh.getCoord();
                    if (ponto.x > -1)
                        fillRectangle(g, ponto, TAM, Pesos.getCorPorPeso(noh.getPeso()));
                }
            }

            // Pinta o caminho encontrado
            if (!controle.getCaminho().isEmpty()) {
                ArrayList<Point> caminho = controle.getCaminho();
                for (Point ponto : caminho)
                    fillRectangle(g, ponto, TAM, Color.PINK);
            }
        }

        /**
         * Método que preenche os quadrados
         * @param graphics objeto graphics do componente a ser pintado
         * @param ponto    ponto representando a coordenada do quadrado a ser pintado
         * @param TAM      tamanho do quadrado
         * @param color    cor do quadrado
         */
        private void fillRectangle(Graphics graphics, Point ponto, int TAM, Color color) {
            graphics.setColor(color);
            graphics.fillRect((ponto.x + 1) * TAM + 1, (ponto.y + 1) * TAM + 1, TAM - 1, TAM - 1);
        }
    }

    /**
     * Classe que representa o painel que exibe as informações a respeito
     * do caminho encontrado.
     */
    private class PainelInfo extends JPanel {
        private JLabel custoCaminho;
        private JLabel tamanhoCaminho;

        public PainelInfo() {
            this.setLayout(new GridLayout(2, 1, 5, 5));
            custoCaminho = new JLabel("Custo do Caminho = ", JLabel.CENTER);
            tamanhoCaminho = new JLabel("Tamanho do Caminho = ", JLabel.CENTER);
            this.add(custoCaminho);
            this.add(tamanhoCaminho);
            atualizarLabels(0, 0);
        }

        public void atualizarLabels(int custo, int tamanho) {
            custoCaminho.setText("Custo do caminho = " + custo);
            tamanhoCaminho.setText("Tamanho do caminho = " + tamanho);
        }
    }

}
